﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using Biblioteca.Models;
using System.Data;

namespace Biblioteca.Controllers
{
    
    public class AccountController : Controller
    {
        [Authorize(Roles = "Administrador")]
        public ActionResult Index()
        {
            return RedirectToAction("Admin");
        }


        //
        // GET: /Account/Admin
        [Authorize(Roles = "Administrador")]
        public ActionResult Admin()
        {
            var listaAccounts = new LinkedList<DisplayModel>();
            using (BibliotecaStore db = new BibliotecaStore())
            {
                var listaUsers = (from u in db.Usuarios
                                  select u);

                foreach( Usuario u in listaUsers)
                {
                    //Fila de CuentaUsuario correspondiente al usuario
                    CuentaUsuario acc = (from p in db.CuentaUsuarios
                                        where p.Usuario == u.IdUsuario
                                         select p).FirstOrDefault();

                    //Cuenta correspondiente al usuario
                    Cuenta cta = (from c in db.Cuentas
                                  where c.IdCuenta == acc.Cuenta
                                  select c).FirstOrDefault();
                    
                    //Tipo del usuario
                    TipoUsuario tipo = db.TipoUsuarios.Single(t => t.IdTipoUser == u.Tipo);

                    //Creo el modelo con la informacion pertinente a mostrar
                    DisplayModel infoUser = new DisplayModel();
                    infoUser.IdCuenta= cta.IdCuenta;
                    infoUser.IdUsuario = u.IdUsuario;
                    infoUser.Nombre = u.Nombre;
                    infoUser.Apellido = u.Apellido;
                    infoUser.UserName = cta.Usuario;
                    infoUser.TipoUsuario = tipo.Descripcion;
                    if (acc.Activada == 1)
                        infoUser.Activo = true;
                    else
                        infoUser.Activo = false;

                    //Agrego el modelo a la lista
                    listaAccounts.AddLast(infoUser);
                }

            }

       //     ViewBag.lista = listaAccounts;

            return View(listaAccounts);
        }

        //
        // GET: /Account/LogOn

        public ActionResult LogOn()
        {
            return View();
        }

        //
        // POST: /Account/LogOn

        [HttpPost]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "El nombre de usuario o password son incorrectos.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // GET: /Account/LogOff

        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();

            return RedirectToAction("Index", "Home");
        }

        //
        // GET: /Account/Register

        public ActionResult Register()
        {
            return View();
        }

        //
        // POST: /Account/Register

        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Crea la Cuenta con ese username y pass, si se puede
                MembershipCreateStatus createStatus;
                Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);


                //Si se pudo, hay que crear el Usuario y linkearlos en CuentaUsuario
                if (createStatus == MembershipCreateStatus.Success)
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);
                    
                    using (BibliotecaStore db = new BibliotecaStore())
                    {
                        //Buscar la cuenta que se acaba de crear
                        Cuenta cta = (from u in db.Cuentas
                                      where u.Usuario == model.UserName
                                      select u).FirstOrDefault();
                                          
                        //Registrar el Usuario y linkear ambos en CuentaUsuario
                        Usuario user = new Usuario();
                        user.Nombre = model.Nombre;
                        user.Apellido = model.Apellido;
                        user.Domicilio = model.Domicilio;
                        user.Email = model.Email.ToLower();
                        user.Tipo = 2;          //2 = SocioBiblioteca, por defecto
                        db.Usuarios.AddObject(user);
                        db.SaveChanges();

                        CuentaUsuario cta_us = new CuentaUsuario();
                        cta_us.Cuenta = cta.IdCuenta;
                        cta_us.Usuario = user.IdUsuario;
                        cta_us.Activada = 1;
                        db.CuentaUsuarios.AddObject(cta_us);
                        db.SaveChanges();
                    }

                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    ModelState.AddModelError("", ErrorCodeToString(createStatus));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // GET: /Account/CambiarEstado/5
        [Authorize(Roles = "Administrador")]
        public ActionResult CambiarEstado(string username)
        {
            MyMembershipProvider myMembership = (MyMembershipProvider)System.Web.Security.Membership.Providers["CustomMembershipProvider"];

            if (myMembership.cambiarEstadoActivacion(username))
            {
                ViewBag.cambioEstado = "El cambio de estado fue exitoso";
            }
            else
            {
               return RedirectToAction("NoPermission");
            }

            return RedirectToAction("Admin");
        }

        //GET: /Account/CambiarRol/5
        [Authorize(Roles = "Administrador")]
        public ActionResult CambiarRol(int idUsuario)
        {
            using (BibliotecaStore db = new BibliotecaStore())
            {
                Usuario user = db.Usuarios.Single(u => u.IdUsuario == idUsuario);
                CuentaUsuario cta_us = db.CuentaUsuarios.Single(t => t.Usuario == user.IdUsuario);
                Cuenta cta = db.Cuentas.Single(c => c.IdCuenta == cta_us.Cuenta);

                List<Cuenta> list = new List<Cuenta>(); list.Add(cta);
                ViewBag.cuenta = cta.Usuario;
                //OrderBy el campo a ordenar, el nombre de la variable cuando retorne el submit, el campo del que se mostraran valores en la lista
                ViewBag.tipos = new SelectList(db.TipoUsuarios.ToList().OrderBy(t => t.Descripcion), "Descripcion", "Descripcion");

            }

            return View();
        }

        //
        // POST
        [Authorize(Roles = "Administrador")]
        [HttpPost]
        public ActionResult CambiarRol(FormCollection form)
        {
            string roleName = form.Get("tipos");
            string username = form.Get("cuenta");

            MyRoleProvider roleProvider = (MyRoleProvider)System.Web.Security.Roles.Providers["CustomRoleProvider"];
            string[] user = new string[1];
            user[0] = username;
            string[] roles = new string[1];
            roles[0] = roleName;

            if (roleName == "") //Si no se eligio ningun Rol en el form
            {
                return RedirectToAction("Admin");
            }

            if (username != null && roleName != null)
            {
                roleProvider.AddUsersToRoles(user, roles);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }

            return RedirectToAction("Admin");
        }

        //
        //GET: /Account/Edit/5
        [Authorize(Roles = "Administrador")]
        public ActionResult Edit(string idCuenta)
        {
            RegisterModel model = new RegisterModel();

            using (BibliotecaStore db = new BibliotecaStore())
            {
                int id;
                bool valid = int.TryParse(idCuenta,out id);

                if (valid)
                {

                    Cuenta cta = db.Cuentas.Single(e => e.IdCuenta == id);
                    CuentaUsuario cta_us = db.CuentaUsuarios.Single(p => p.Cuenta == cta.IdCuenta);
                    Usuario user = db.Usuarios.Single(u => u.IdUsuario == cta_us.Usuario);

                    model.IdCuenta = cta.IdCuenta.ToString();
                    model.IdUsuario = user.IdUsuario.ToString();
                    model.Nombre = user.Nombre;
                    model.Apellido = user.Apellido;
                    model.Domicilio = user.Domicilio;
                    model.Email = user.Email;
                    model.UserName = cta.Usuario;
                    model.Password = cta.Password;
                    model.ConfirmPassword = cta.Password;
                }
                else
                {
                    ModelState.AddModelError("", "El ID de la cuenta no es un entero valido...");
                }

            }

            //Muestra el form de edicion con los campos llenos
            return View(model);
        }

        [HttpPost]
        public ActionResult Edit(RegisterModel model)
        {

            if (ModelState.IsValid)
            {
                using (BibliotecaStore db = new BibliotecaStore())
                {
                    //La cuenta que se desea editar
                    int id;
                    bool valido = int.TryParse(model.IdCuenta,out id);
                    if (valido)
                    {
                        Cuenta cta = db.Cuentas.Single(e => e.IdCuenta == id);
                        CuentaUsuario cta_us = db.CuentaUsuarios.Single(p => p.Cuenta == cta.IdCuenta);
                        Usuario user = db.Usuarios.Single(u => u.IdUsuario == cta_us.Usuario);

                        /*
                        //Buscar la cuenta que se desea editar
                        Cuenta cta = (from u in db.Cuentas
                                      where u.IdCuenta == Int32.Parse(model.IdCuenta)
                                      select u).FirstOrDefault();

                        //Buscar el Usuario que se desea editar (el unico vinculado con 'cta')
                        Usuario user = (from u in db.Usuarios
                                        join p in db.CuentaUsuarios on u.IdUsuario equals p.Usuario
                                        where cta.IdCuenta == p.Cuenta
                                        select u).FirstOrDefault();

                        CuentaUsuario cta_us = (from p in db.CuentaUsuarios
                                                where p.Cuenta == cta.IdCuenta && p.Usuario == user.IdUsuario
                                                select p).FirstOrDefault();
                        */
                        user.Nombre = model.Nombre;
                        user.Apellido = model.Apellido;
                        user.Domicilio = model.Domicilio;
                        user.Email = model.Email.ToLower();

                        cta.Usuario = model.UserName;
                        cta.Password = model.Password;

                        cta_us.Cuenta = cta.IdCuenta;
                        cta_us.Usuario = user.IdUsuario;

                        db.ObjectStateManager.ChangeObjectState(cta, EntityState.Modified);
                        db.ObjectStateManager.ChangeObjectState(user, EntityState.Modified);
                        db.ObjectStateManager.ChangeObjectState(cta_us, EntityState.Modified);
                        db.SaveChanges();
                    }
                    else
                    {
                        //No es valido el id de la cuenta...no es un entero
                    }
                }

                return RedirectToAction("Admin");
            }
            else
            {
                ModelState.AddModelError("", "Hay algun error en algun campo!");
            }

            //Se llega aca si hubo algun error, se devuelve el form
            return View(model);
        }

        //
        // GET: /Editorial/Delete/5
        [Authorize(Roles = "Administrador")]
        public ActionResult Delete(string idCuenta, string idUsuario)
        {
            using (BibliotecaStore db = new BibliotecaStore())
            {
                int idCta, idUser;
                bool ctaValid = int.TryParse(idCuenta, out idCta);
                bool userValid = int.TryParse(idUsuario, out idUser);

                if (ctaValid && userValid)
                {
                    //Obtengo los objetos a eliminar
                    Cuenta cta = db.Cuentas.Single(c => c.IdCuenta == idCta);
                    Usuario user = db.Usuarios.Single(u => u.IdUsuario == idUser);
                    CuentaUsuario cta_us = db.CuentaUsuarios.Single(t => t.Cuenta == cta.IdCuenta && t.Usuario == user.IdUsuario);
                    string tipo = db.TipoUsuarios.Single(t => t.IdTipoUser == user.Tipo).Descripcion;

                    //Creo el modelo que usara la vista y lo lleno
                    DisplayModel model = new DisplayModel();
                    model.IdCuenta = cta.IdCuenta;
                    model.IdUsuario = user.IdUsuario;
                    model.Nombre = user.Nombre;
                    model.Apellido = user.Apellido;
                    model.UserName = cta.Usuario;
                    model.TipoUsuario = tipo;
                    if (cta_us.Activada == 1)
                        model.Activo = true;
                    else
                        model.Activo = false;

                    //Mando el modelo a la vista.
                    return View(model);
                }
                else
                {
                    //Id de cuenta o usuario no valido ?
                    return RedirectToAction("Admin");
                }
            }

        }

        //
        // POST: /Editorial/Delete/5

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int idUsuario, int idCuenta)
        {

            using (BibliotecaStore db = new BibliotecaStore())
            {
               //Obtengo los objetos a eliminar
                Cuenta cta = db.Cuentas.Single(c => c.IdCuenta == idCuenta);
                Usuario user = db.Usuarios.Single(u => u.IdUsuario == idUsuario);
                CuentaUsuario cta_us = db.CuentaUsuarios.Single(t => t.Cuenta == cta.IdCuenta && t.Usuario == user.IdUsuario);

                //Los elimino (en orden para respetar las FK)
                db.CuentaUsuarios.DeleteObject(cta_us);
                db.SaveChanges();
                db.Cuentas.DeleteObject(cta);
                db.Usuarios.DeleteObject(user);
                db.SaveChanges();

                //Retorno al listado, Admin
                return RedirectToAction("Admin");
            }

        }

        //
        // GET: /Account/ChangePassword

        [Authorize]
        public ActionResult ChangePassword()
        {
            return View();
        }

        //
        // POST: /Account/ChangePassword

        [Authorize]
        [HttpPost]
        public ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (ModelState.IsValid)
            {

                // ChangePassword will throw an exception rather
                // than return false in certain failure scenarios.
                bool changePasswordSucceeded;
                try
                {
                    MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
                    changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword);
                }
                catch (Exception)
                {
                    changePasswordSucceeded = false;
                }

                if (changePasswordSucceeded)
                {
                    return RedirectToAction("ChangePasswordSuccess");
                }
                else
                {
                    ModelState.AddModelError("", "El password actual es incorrecto o el nuevo password es inválido.");
                }
            }

            // Si llego hasta acá hubo algun error, mostrar nuevamente el form
            return View(model);
        }

        //
        // GET: /Account/ChangePasswordSuccess

        public ActionResult ChangePasswordSuccess()
        {
            return View();
        }

        public ActionResult NoPermission()
        {
            return View();
        }

        #region Status Codes
        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "El nombre de usuario ingresado ya se encuentra en uso. Por favor ingrese un nombre diferente.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "Ya existe un nombre de usuario para esa cuenta de email. Por favor ingrese un email válido diferente.";

                case MembershipCreateStatus.InvalidPassword:
                    return "El password ingresado es inválido. Por favor ingrese un valor de password válido.";

                case MembershipCreateStatus.InvalidEmail:
                    return "La dirección de email ingresada es inválida. Por favor revise este valor e intente nuevamente.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "El nombre de usuario ingresado no es válido o ya está en uso. Intente nuevamente.";

                case MembershipCreateStatus.ProviderError:
                    return "Ocurrió un error del servidor de autenticación. Verifique los datos e intente nuevamente. Si el problema persiste, contacte al administrador del sistema.";

                case MembershipCreateStatus.UserRejected:
                    return "Se rechazó la creación de usuario. Verifique los datos e intente nuevamente. Si el problema persiste, contacte al administrador del sistema.";

                default:
                    return "Ocurrió un error inesperado. Verifique los datos e intente nuevamente. Si el problema persiste, contacte al administrador del sistema.";
            }
        }
        #endregion
    }
}
